package com.csust.automaticteach.controller;

/**
 * @ClassName LearnChatController
 * @Description 聊天学习控制器
 * @Author钰玟
 * @Date2025/6/17 下午3:33
 * @Version 1.0
 **/

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import com.alibaba.cloud.ai.dashscope.api.DashScopeApi;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.csust.automaticteach.common.BaseResponse;
import com.csust.automaticteach.common.DeleteRequest;
import com.csust.automaticteach.common.ResultUtils;
import com.csust.automaticteach.constant.UserAuthConstant;
import com.csust.automaticteach.exception.BusinessException;
import com.csust.automaticteach.exception.ErrorCode;
import com.csust.automaticteach.exception.ThrowUtils;
import com.csust.automaticteach.model.dto.learnchat.LearnChatAddRequest;
import com.csust.automaticteach.model.dto.learnchat.LearnChatQueryRequest;
import com.csust.automaticteach.model.dto.learnchat.LearnChatUpdateRequest;
import com.csust.automaticteach.model.entity.LearnChat;
import com.csust.automaticteach.model.entity.User;
import com.csust.automaticteach.model.enums.ChatSchemaEnum;
import com.csust.automaticteach.service.BaseService;
import com.csust.automaticteach.service.LearnChatService;
import com.csust.automaticteach.service.UserService;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.http.MediaType;
import org.springframework.http.codec.ServerSentEvent;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.*;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;

import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.Set;

/**
 * 学习聊天的对外服务接口控制器
 */
@RestController
@RequestMapping("/chat")
public class LearnChatController {

    private final UserService userService;
    private final LearnChatService learnChatService;
    private final BaseService baseService;
    public LearnChatController(UserService userService,LearnChatService learnChatService, BaseService baseService) {
        this.userService = userService;
        this.learnChatService = learnChatService;
        this.baseService = baseService;
    }
    @GetMapping("/list/model")
    public BaseResponse<List<ModelView>> listModel() {
        // 得到模型列表
        Set<Map<String, String>> dashScope = baseService.getDashScope();
        List<ModelView> modelViews = dashScope.stream().map(map -> new ModelView(map.get("model"), map.get("desc"))).toList();
        return ResultUtils.success(modelViews);
    }
    /**
     * 可选择模型来进行学习聊天（流式 SSE）
     *
     * @param learnChatId   聊天会话ID
     * @param message 用户消息
     * @param model 模型名称
     * @param request 请求对象
     * @return 生成结果流
     */
    @GetMapping(value = "/chat/model/learn", produces = MediaType.TEXT_EVENT_STREAM_VALUE)
    public Flux<ServerSentEvent<String>> chatToLearn(@RequestParam Long learnChatId,
                                    @RequestParam String message,
                                     @RequestParam(defaultValue = "qwen-turbo", required = false) String model,
                                    @RequestParam(value = "promptId", required = false,defaultValue = "0") String promptId,
                                    HttpServletRequest request,
                                    HttpServletResponse response) {
        // 参数校验
        ThrowUtils.throwIf(learnChatId == null || learnChatId <= 0, ErrorCode.PARAMS_ERROR, "应用ID无效");
        ThrowUtils.throwIf(promptId == null || Long.parseLong(promptId) < 0, ErrorCode.PARAMS_ERROR, "提示词ID无效");
        ThrowUtils.throwIf(StrUtil.isBlank(message), ErrorCode.PARAMS_ERROR, "用户消息不能为空");
        // 获取当前登录用户
        User loginUser = userService.getLoginUser(request);
        //得到模型列表
        Set<Map<String, String>> dashScope = baseService.getDashScope();//获取模型列表
        List<String> modelName = dashScope.stream()
                .flatMap(map -> map.keySet().stream().map(map::get))
                .distinct()
                .toList();
        if (StringUtils.hasText(model)) {
            if (!modelName.contains(model)) {
//                return Flux.just("Input model not support.");
                throw new BusinessException(ErrorCode.PARAMS_ERROR,"Input model not support.");
            }
        }
        else {
            model = DashScopeApi.ChatModel.QWEN_PLUS.getValue();
        }
        response.setCharacterEncoding("UTF-8");
        // 调用服务生成代码（流式）
        return learnChatService.chatToLearn(learnChatId,message,model,promptId,loginUser,ChatSchemaEnum.CHAT_LEARN).map(chunk -> {
                    // 将内容包装成JSON对象
                    Map<String, String> wrapper = Map.of("d", chunk);
                    String jsonData = JSONUtil.toJsonStr(wrapper);
                    return ServerSentEvent.<String>builder()
                            .data(jsonData)
                            .build();
                })
                .concatWith(Mono.just(
                        // 发送结束事件
                        ServerSentEvent.<String>builder()
                                .event("done")
                                .data("")
                                .build()
                ));
    }
    /**
     * 可选择模型来进行学习聊天（流式 SSE）
     *
     * @param learnChatId   聊天会话ID
     * @param message 用户消息
     * @param model 模型名称
     * @param request 请求对象
     * @return 生成结果流
     */
    @GetMapping(value = "/deep-thinking/chat/model/learn", produces = MediaType.TEXT_EVENT_STREAM_VALUE)
    public Flux<ServerSentEvent<String>>  deepThinkingChatToLearn(@RequestParam Long learnChatId,
                                    @RequestParam String message,
                                    @RequestParam(defaultValue = "qwen-turbo", required = false) String model,
                                    @RequestParam(value = "promptId", required = false,defaultValue = "0") String promptId,
                                    HttpServletRequest request,
                                    HttpServletResponse response) {
        // 参数校验
        ThrowUtils.throwIf(learnChatId == null || learnChatId <= 0, ErrorCode.PARAMS_ERROR, "应用ID无效");
        ThrowUtils.throwIf(promptId == null || Long.parseLong(promptId) < 0, ErrorCode.PARAMS_ERROR, "提示词ID无效");
        ThrowUtils.throwIf(StrUtil.isBlank(message), ErrorCode.PARAMS_ERROR, "用户消息不能为空");
        // 获取当前登录用户
        User loginUser = userService.getLoginUser(request);
        //得到模型列表
        Set<Map<String, String>> dashScope = baseService.getDashScope();//获取模型列表
        List<String> modelName = dashScope.stream()
                .flatMap(map -> map.keySet().stream().map(map::get))
                .distinct()
                .toList();
        if (StringUtils.hasText(model)) {
            if (!modelName.contains(model)) {
//                return Flux.just("Input model not support.");
                throw new BusinessException(ErrorCode.PARAMS_ERROR,"Input model not support.");
            }
        }
        else {
            model = DashScopeApi.ChatModel.QWEN_PLUS.getValue();
        }
        response.setCharacterEncoding("UTF-8");
        // 调用服务生成代码（流式）
        return learnChatService.chatToLearn(learnChatId,message,model,promptId,loginUser,ChatSchemaEnum.DEEP_THINKING).map(chunk -> {
                    // 将内容包装成JSON对象
                    Map<String, String> wrapper = Map.of("d", chunk);
                    String jsonData = JSONUtil.toJsonStr(wrapper);
                    return ServerSentEvent.<String>builder()
                            .data(jsonData)
                            .build();
                })
                .concatWith(Mono.just(
                        // 发送结束事件
                        ServerSentEvent.<String>builder()
                                .event("done")
                                .data("")
                                .build()
                ));
    }
    /**
     * 创建应用
     *
     * @param learnChatAddRequest 创建聊天请求
     * @param request       请求
     * @return 应用 id
     */
    @PostMapping("/add")
    public BaseResponse<Long> addLearnChat(@RequestBody LearnChatAddRequest learnChatAddRequest, HttpServletRequest request) {
        ThrowUtils.throwIf(learnChatAddRequest == null, ErrorCode.PARAMS_ERROR);
        // 参数校验
        String initPrompt = learnChatAddRequest.getInitPrompt();
        ThrowUtils.throwIf(StrUtil.isBlank(initPrompt), ErrorCode.PARAMS_ERROR, "初始化 prompt 不能为空");
        // 获取当前登录用户
        User loginUser = userService.getLoginUser(request);
        ThrowUtils.throwIf(loginUser == null, ErrorCode.NOT_LOGIN_ERROR);
        // 构造入库对象
        LearnChat learnChat = new LearnChat();
        BeanUtil.copyProperties(learnChatAddRequest, learnChat);
        learnChat.setUserId(loginUser.getId());
        // 应用名称暂时为 initPrompt 前 12 位
        learnChat.setTitle(initPrompt.substring(0, Math.min(initPrompt.length(), 12)));
        // 插入数据库
        boolean result = learnChatService.save(learnChat);
        ThrowUtils.throwIf(!result, ErrorCode.OPERATION_ERROR);
        return ResultUtils.success(learnChat.getId());
    }
    /**
     * 更新会话标题（用户只能更新自己的应用名称）
     *
     * @param learnChatUpdateRequest 更新请求
     * @param request          请求
     * @return 更新结果
     */
    @PostMapping("/update")
    public BaseResponse<Boolean> updateLearnChat(@RequestBody LearnChatUpdateRequest learnChatUpdateRequest, HttpServletRequest request) {
        if (learnChatUpdateRequest == null || learnChatUpdateRequest.getId() == null) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR);
        }
        User loginUser = userService.getLoginUser(request);
        long id = learnChatUpdateRequest.getId();
        // 判断是否存在
        LearnChat oldApp = learnChatService.getById(id);
        ThrowUtils.throwIf(oldApp == null, ErrorCode.NOT_FOUND_ERROR);
        // 仅本人可更新
        if (!oldApp.getUserId().equals(loginUser.getId())) {
            throw new BusinessException(ErrorCode.NO_AUTH_ERROR);
        }
        LearnChat learnChat = new LearnChat();
        learnChat.setId(id);
        learnChat.setTitle(learnChatUpdateRequest.getTitle());
        // 设置编辑时间
        learnChat.setEditTime(new Date());
        boolean result = learnChatService.updateById(learnChat);
        ThrowUtils.throwIf(!result, ErrorCode.OPERATION_ERROR);
        return ResultUtils.success(true);
    }
    /**
     * 删除应用（用户只能删除自己的应用）
     *
     * @param deleteRequest 删除请求
     * @param request       请求
     * @return 删除结果
     */
    @PostMapping("/delete")
    public BaseResponse<Boolean> deleteLearnChat(@RequestBody DeleteRequest deleteRequest, HttpServletRequest request) {
        if (deleteRequest == null || deleteRequest.getId() <= 0) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR);
        }
        User loginUser = userService.getLoginUser(request);
        long id = deleteRequest.getId();
        // 判断是否存在
        LearnChat oldLearnChat = learnChatService.getById(id);
        ThrowUtils.throwIf(oldLearnChat == null, ErrorCode.NOT_FOUND_ERROR);
        // 仅本人或管理员可删除
        if (!oldLearnChat.getUserId().equals(loginUser.getId()) && !UserAuthConstant.ADMIN_ROLE.equals(loginUser.getUserRole())) {
            throw new BusinessException(ErrorCode.NO_AUTH_ERROR);
        }
        boolean result = learnChatService.removeById(id);
        return ResultUtils.success(result);
    }
    /**
     * 分页获取当前用户创建的应用列表
     *
     * @param learnChatQueryRequest 查询请求
     * @param request         请求
     * @return 应用列表
     */
    @PostMapping("/my/list/page/vo")
    public BaseResponse<Page<LearnChat>> listMyLearnChatVOByPage(@RequestBody LearnChatQueryRequest learnChatQueryRequest, HttpServletRequest request) {
        ThrowUtils.throwIf(learnChatQueryRequest == null, ErrorCode.PARAMS_ERROR);
        User loginUser = userService.getLoginUser(request);
        long pageSize = learnChatQueryRequest.getPageSize() < 0 ? 10 : learnChatQueryRequest.getPageSize() ;
        ThrowUtils.throwIf(pageSize > 20, ErrorCode.PARAMS_ERROR, "每页最多查询 20 个会话记录");
        // 只查询当前用户的应用
        learnChatQueryRequest.setUserId(loginUser.getId());
        QueryWrapper<LearnChat> queryWrapper = learnChatService.getQueryWrapper(learnChatQueryRequest);
        Page<LearnChat> learnChatPage = learnChatService.page(Page.of(1, pageSize), queryWrapper);
        return ResultUtils.success(learnChatPage);
    }

    public record ModelView(String modelName, String description){
        public ModelView(String modelName, String description) {
            this.modelName = modelName;
            this.description = description;
        }
    }


}
